<template>
    <div>
        <el-upload class="image-uploader" v-model:file-list="fileList" action="#" multiple :limit="limit"
            list-type="picture-card" accept="image/*,.pdf" :http-request="handleXhr" :before-upload="handleBeforeUpload"
            :on-preview="handlePreview" :on-remove="handleRemove" :on-exceed="handleExceed">
            <el-icon>
                <Plus />
            </el-icon>
        </el-upload>

        <el-dialog v-model="dialogVisible">
            <img w-full :src="dialogImageUrl" style="width:100%; max-height:60vh;" alt="Preview Image" />
        </el-dialog>
    </div>
</template>
  
<script setup>
/**
 * 图片上传组件
 */
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import EsAjax from '@/utils/EsAjax';
import ApiUrls from '@/apis/index';

// ======================================================
//                      功能函数
// ======================================================

/**
 * 字节单位转换
 */
const bytesToSize = (bytes) => {
    if (bytes === 0) {
        return '0 B';
    }
    var k = 1024, // or 1024
        sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
        i = Math.floor(Math.log(bytes) / Math.log(k));

    return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
}

// ======================================================
//                      变量声明
// ======================================================

// props
const props = defineProps({
    modelValue: Array,
    limit: {
        type: Number,
        default: 5
    },
    maxSize: {
        type: Number,
        default: 500 * 1024,
    }
})
// emit（v-model 使用在原生控件为: value @input，使用在组件为: modelValue @update:modelValue）
const emit = defineEmits(['update:modelValue']);
// 文件路径 [{name,url}]
const fileList = ref(props.modelValue);
const files = ref(props.modelValue);
// watch
watch(() => props.modelValue, (newVal) => {
    fileList.value = newVal;
    files.value = newVal;
})
// 文件类型
const imageMimes = ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp']
// 文件大小提示
const maxSizeText = bytesToSize(props.maxSize);
// 图片预览弹窗
const dialogImageUrl = ref('')
const dialogVisible = ref(false)

// ======================================================
//                      处理事件
// ======================================================

// 处理上传文件之前的钩子
const handleBeforeUpload = (rawFile) => {
    if (!imageMimes.includes(rawFile.type)) {
        ElMessage.error('文件不是有效的图片格式！')
        return false;
    }
    if (rawFile.size > props.maxSize) {
        ElMessage.error('单个文件不能超过 ' + maxSizeText + '!')
        return false;
    }
    return true
}

// 处理上传文件的请求
const handleXhr = (xhr) => {
    let formData = new FormData();
    formData.set('file', xhr.file);
    EsAjax.post(ApiUrls.upload, formData).then(res => {
        if (res.data.errcode) {
            ElMessage.warning(res.data.data+res.data.msg);
            return;
        }
        files.value = files.value.concat(res.data.data);
        emit('update:modelValue', files.value);
    }).catch(err => { ElMessage.error('网络错误：' + err.message) })
}

// 处理文件列表移除文件时的钩子
const handleRemove = (uploadFile, uploadFiles) => {
    files.value = [];
    uploadFiles.forEach(item => {
        files.value.push({ name: item.name, url: item.url });
    })
}

// 处理点击文件列表中已上传的文件时的钩子
const handlePreview = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url
    dialogVisible.value = true
}

// 处理超出限制时的钩子
const handleExceed = (files, uploadFiles) => {
    ElMessage.warning(
        `最多上传  ${props.limit} 个文件，您刚选择 ${files.length} 个文件，累计 ${files.length + uploadFiles.length} 个文件。`
    )
}

</script>
  